package com.wang.utils.linklist;

import java.net.HttpRetryException;
import java.util.Stack;

/**
 * @author 10570
 * @date 2021/7/12 21:27
 */


public class SingleLinkedListDemo {
    public static void main(String[] args) {
        HeroNode heroNode1 = new HeroNode(1,"宋江","及时雨");
        HeroNode heroNode2 = new HeroNode(2,"lujunyi","玉麒麟");
        HeroNode heroNode3 = new HeroNode(3,"吴用","智多星");
        HeroNode heroNode4 = new HeroNode(4,"林冲","豹子头");

        SingleLinkedList singleLinkedList = new SingleLinkedList();
        //加入
//        singleLinkedList.add(heroNode3);
//        singleLinkedList.add(heroNode1);
//        singleLinkedList.add(heroNode2);
//        singleLinkedList.add(heroNode4);
        singleLinkedList.addByOrder(heroNode3);
        singleLinkedList.addByOrder(heroNode1);
        singleLinkedList.addByOrder(heroNode2);
        singleLinkedList.addByOrder(heroNode4);
        singleLinkedList.show();
        System.out.println("逆序打印");
        reversePrint(singleLinkedList.getHead());
     /* System.out.println("反转");
        reverseHeroNode(singleLinkedList.getHead());
        singleLinkedList.show();*/
        /*
//        singleLinkedList.addByOrder(heroNode1);
        singleLinkedList.update(new HeroNode(1,"江江","吉吉"));
        singleLinkedList.delete(1);
        singleLinkedList.show();

        singleLinkedList.delete(4);
        singleLinkedList.show();
        singleLinkedList.delete(2);
        singleLinkedList.show();
        singleLinkedList.delete(1);
        singleLinkedList.show();
        System.out.println(singleLinkedList.getHead());

        System.out.println();
        HeroNode res = findListNode(singleLinkedList.getHead(),2);
        System.out.println(res);
        */
    }

    //重尾到头打印单链表
    /**
     *     1、将单链表反转，再打印
     *     会破坏原有的链表结构
     *     2、利用栈，将各个节点压入到栈中，利用栈的现金后出的特性
     *     栈的理解：先入后出，利用了栈的特性
     *
     */
    public static void reversePrint(HeroNode heroNode){
        if (heroNode.next==null){
            return;
        }
        Stack<HeroNode> stack = new Stack();
        HeroNode current = heroNode.next;
        while (current != null){
            stack.push(current);
            current = current.next; //将current后移
        }
        //将栈中的节点打印
        while (stack.size()>0){
            System.out.println(stack.pop()); //逆序打印
        }
    }

    //

    //单链表反转--将节点的位置变换
    /**
     * 1、定义一个节点  reverseHead = new HeroNode（）
     * 2、从头到尾遍历一个链表，每遍历一个节点就放到新的链表最前边
     * 3、原来的头节点  head.next = reverseHead.next
     */
    public static void reverseHeroNode(HeroNode heroNode){
        //判断是否为空，或者只有一个节点
        if (heroNode.next == null || heroNode.next.next == null){
            return;
        }
        //定义辅助变量，帮助遍历
        HeroNode current = heroNode.next;
        HeroNode next = null;
        HeroNode reverseHead = new HeroNode();
        //遍历
        while (current != null){
            //暂时保存当前节点的下一个节点
            next = current.next;
            //将current的下一个节点，指向reverseHead的头节点
            current.next = reverseHead.next;
            reverseHead.next= current;  //将current链接到新的链表上
            current = next;
        }
        //将head.next 指向reversehead.next
        heroNode.next = reverseHead.next;
    }




    //方法：获取到单链表的节点的个数（如果头节点为空，不统计头节点）
    /**
     * 获取有效节点
     * @param heroNode
     * @return
     */
    public static int getLength(HeroNode heroNode){
        if (heroNode.next == null){
            return 0;

        }
        int length = 0;
        HeroNode current = heroNode.next;
        while (current != null){
            length++;
            current = current.next; // 遍历
        }
        return length;
    }

    //查找单链表的第k个节点
    //1、编写一个方法，接收head节点，同时接收一个head值
    //2、index 表示 倒数 第index个节点
    //3、先把链表从头开始遍历，得到链表的总长度getLength
    //4、得到size后，我们从链表的第一个开始遍历(size-index)，就可以得到
    public static HeroNode findListNode(HeroNode heroNode,int index){
        if (heroNode == null){
            return null;
        }
        //先获得总长
        int size = getLength(heroNode);
        //第二次， size-index的位置，就是我们需要的节点
        if (index <=0 || index > size ){
            return null;
        }
        //定义辅助变量
        HeroNode current = heroNode.next;
        for (int i = 0; i< size-index;i++){
            current = current.next;

        }
        return current;
    }

}

//定义管理英雄
class SingleLinkedList{
    //先定义一个头节点
    private HeroNode head = new HeroNode(0,"","");

    //返回头节点


    public HeroNode getHead() {
        return head;
    }

    public void setHead(HeroNode head) {
        this.head = head;
    }

    //添加节点到heroNode
    //当不考虑编号顺序时：
    //1、找到当前链表的最后节点
    //2、将最后这个节点的next执行  新的节点
    public void add(HeroNode heroNode){
        //head节点不动  需要一个辅助遍历  temp
        HeroNode temp = head;
        while (true){
            //找到链表的最后
            if (temp.next == null){
                break;
            }
            //如果没有找到后移
            temp = temp.next;
        }
        //退出循环时，temp指向链表的最后
        temp.next = heroNode;
    }

    public void addByOrder(HeroNode heroNode){
        //因为头节点不动，需要辅助变量来找到位置
        //找到位置为添加位置的前一个节点
        HeroNode temp = head;
        boolean flag = false;//作为是否存在的判断
        while (true){
            //最后为空就不能添加了
            if (temp.next == null){
                break;
            }
            if (temp.next.root > heroNode.root){
                break;
            }else if (temp.next.root == heroNode.root){
                flag = true; //说明编号存在
                break;

            }
            temp = temp.next;
        }
        //判断flag
        if (flag){
            System.out.println("英雄编号已存在不能添加:"+heroNode.root);
        }else {
            //插入到链表中
            heroNode.next = temp.next;
            temp.next = heroNode;
        }
    }


    @Override
    public String toString() {
        return "SingleLinkedList{" +
                "head=" + head +
                '}';
    }

    //显示链表
    public void show(){
        //先判断链表是否为空
        if (head.name == null){
            System.out.println("链表为空");
            return;
        }
        //头节点不能动，因此需要一个辅助变量遍历
        HeroNode temp = head.next;

        while (true){
            //判断是否为空
            if (temp == null){
                break;
            }
            System.out.println(temp);
            //将next后移
            temp = temp.next;
        }
    }
    //修改节点信息根据编号来修改，编号不变
    public void update(HeroNode newHeroNode){
        //根据heroNode.root来修改
        if (head.next == null){
            System.out.println("链表为空");
            return;
        }
        //定义辅助 变量
        HeroNode temp = head.next;
        boolean flag = false; // 表示是否找到节点
        while (true){
            if (temp == null){
                System.out.println("倒了链表最后");
                break;
            }
            if (temp.root == newHeroNode.root){
                flag = true;
                break;
            }
            temp = temp.next;


        }
        if (flag){
            temp.name = newHeroNode.name;
            temp.nickName = newHeroNode.nickName;
        }else {
            System.out.printf("没有找到编号为%d，不能修改",newHeroNode.root);
        }
    }
    //删除节点
    //1、辅助变量，找到要删除的节点的前一个节点
    //2、temp.next = temp.next.next
    //将temp.next.root 与需要删除的节点的root比较
    //3、被删除的节点没有其他引用，将会被gc回收
    public void delete(int root){
        HeroNode temp = head;
        boolean flag = false;
        while (true){
            if (temp.next == null){
                break;
            }
            if (temp.next.root == root){
                //找到要删除的节点的前一个节点temp
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            //找到可以删除
            temp.next = temp.next.next;

        }else {
            System.out.printf("没有找到要删除的节点%d",root);
        }

    }


}
//定义heroNode
class HeroNode{
    int root;
    String name;
    String  nickName;
    HeroNode next;  //指向下一个节点

    public HeroNode(){
    }
    public HeroNode(int root, String name, String nickName) {
        this.root = root;
        this.name = name;
        this.nickName = nickName;
    }
    //重写toString（）


    @Override
    public String toString() {
        return "HeroNode{" +
                "root=" + root +
                ", name='" + name + '\'' +
                ", nickName='" + nickName +
//                ", next=" + next +
                '}';
    }
}
